/*==============================================================================

  Program: 3D Slicer

  Copyright (c) Seattle Children�s Hospital d/b/a Seattle Children�s Research Institute.

  See COPYRIGHT.txt
  or http://www.slicer.org/copyright/copyright.txt for details.

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

  This file was originally developed by Csaba Pinter, PerkLab, Queen's University
  and was partially supported through the Applied Cancer Research Unit program of Cancer Care
  Ontario with funds provided by the Ontario Ministry of Health and Long-Term Care
  and by Murat Maga (Seattle Children's Research Institute).

==============================================================================*/

#ifndef __qSlicerTerminologyNavigatorWidget_h
#define __qSlicerTerminologyNavigatorWidget_h

// MRMLWidgets includes
#include "qMRMLWidget.h"

// Terminologies includes
#include "qSlicerTerminologiesModuleWidgetsExport.h"

#include "vtkSlicerTerminologyEntry.h"

// CTK includes
#include <ctkPimpl.h>
#include <ctkVTKObject.h>

class qSlicerTerminologyNavigatorWidgetPrivate;

class QColor;
class QTableWidgetItem;
class QItemSelection;
class vtkSlicerTerminologyCategory;
class vtkSlicerTerminologyType;

/// \brief Qt widget for browsing a terminology dictionary.
///   DICOM properties of the selected entry can also be set if enabled.
class Q_SLICER_MODULE_TERMINOLOGIES_WIDGETS_EXPORT qSlicerTerminologyNavigatorWidget : public qMRMLWidget
{
  Q_OBJECT
  QVTK_OBJECT

  Q_PROPERTY(bool regionSectionVisible READ regionSectionVisible WRITE setRegionSectionVisible)
  Q_PROPERTY(bool overrideSectionVisible READ overrideSectionVisible WRITE setOverrideSectionVisible)

  /// Roles set to the items in the terminology tables uniquely identifying the entries
  enum TerminologyItemDataRole
  {
    CodingSchemeDesignatorRole = Qt::UserRole + 100,
    CodeValueRole,
    // Roles for type items referencing category
    CategoryCodingSchemeDesignatorRole,
    CategoryCodeValueRole,
    CategoryCodeMeaningRole,
    // Last role (always keep last)
    LastTerminologyRole
  };

public:
  /// Constructor
  explicit qSlicerTerminologyNavigatorWidget(QWidget* parent = nullptr);
  /// Destructor
  ~qSlicerTerminologyNavigatorWidget() override;

#ifndef __VTK_WRAP__
  class Q_SLICER_MODULE_TERMINOLOGIES_WIDGETS_EXPORT TerminologyInfoBundle
  {
  public:
    TerminologyInfoBundle();
    TerminologyInfoBundle(vtkSlicerTerminologyEntry* entry, QString name, bool nameAutoGenerated, QColor color, bool colorAutoGenerated, QColor generatedColor);
    ~TerminologyInfoBundle();
    const TerminologyInfoBundle& operator=(const TerminologyInfoBundle& other);
    vtkSlicerTerminologyEntry* GetTerminologyEntry();

    QString Name;
    bool NameAutoGenerated{ true }; // indicates that the name does not contain valuable information
    QColor Color;
    bool ColorAutoGenerated{ true }; // indicates that the color does not contain valuable information
    QColor GeneratedColor;

  private:
    vtkSlicerTerminologyEntry* TerminologyEntry{ nullptr };
  };

  /// Get selection from widget: terminology and meta-data (name, color, auto-generated flags)
  /// \param terminologyInfo Info bundle to get terminology information into
  void terminologyInfo(TerminologyInfoBundle& terminologyInfo);
  /// Set selection to widget: terminology and meta-data (name, color, auto-generated flags)
  void setTerminologyInfo(TerminologyInfoBundle& terminologyInfo);
#endif // __VTK_WRAP__

  /// Populate terminology entry from terminology and anatomy selection
  /// \return Success flag (e.g. fail if no type is selected)
  Q_INVOKABLE bool terminologyEntry(vtkSlicerTerminologyEntry* entry);
  /// Update terminology and anatomy widgets and selections from terminology entry
  /// \return Success flag (e.g. fail if no type is specified in entry)
  Q_INVOKABLE bool setTerminologyEntry(vtkSlicerTerminologyEntry* entry);

  /// Get whether region section are visible
  bool regionSectionVisible() const;

  /// Get whether name and color override section is visible
  bool overrideSectionVisible() const;

  /// Generate name for given terminology
  Q_INVOKABLE static QString nameFromTerminology(vtkSlicerTerminologyEntry* entry);
  /// Generate name for current terminology
  QString nameFromCurrentTerminology();
  /// Get recommended color from type (or type modifier if any) of the given terminology entry
  Q_INVOKABLE static QColor recommendedColorFromTerminology(vtkSlicerTerminologyEntry* entry);
  /// Get recommended color from type (or type modifier if any) of the current terminology in the widget
  QColor recommendedColorFromCurrentTerminology();

public slots:
  /// Show/hide region section section
  void setRegionSectionVisible(bool);

  /// Show/hide name and color override section
  void setOverrideSectionVisible(bool);

protected slots:
  void onTerminologySelectionChanged(int);
  void onCategorySelectionChanged();
  void onSelectAllCategoriesButtonClicked();
  void onTypeSelected(QTableWidgetItem*, QTableWidgetItem*);
  void onTypeCellDoubleClicked(int, int);
  void onTypeModifierSelectionChanged(int);
  void onCategorySearchTextChanged(QString);
  void onTypeSearchTextChanged(QString);

  void onRegionContextSelectionChanged(int);
  void onRegionSelected(QTableWidgetItem*, QTableWidgetItem*);
  void onRegionModifierSelectionChanged(int);
  void onRegionSearchTextChanged(QString);

  void onColorSelected(const QItemSelection& selected, const QItemSelection& deselected);
  void onColorRowDoubleClicked(const QModelIndex& index);

  void onNameChanged(QString);
  void onResetNameClicked();
  void onColorChanged(QColor);
  void onResetColorClicked();

  void onLoadTerminologyClicked();
  void onLoadRegionContextClicked();

  void onRegionExpandButtonUp();
  void onRegionExpandButtonDown();

  void onLogicModified();

  // Set focus on color item in list, name editor or property name search box so that the user can just start typing.
  void setInitialFocus();

signals:
  /// Emitted when selection becomes valid (true argument) or invalid (false argument)
  void selectionValidityChanged(bool);
  /// Emitted when type is double clicked (in terminology mode). It can be interpreted as having made a selection
  void typeDoubleClicked();
  /// Emitted when color is double clicked (in color mode). It can be interpreted as having made a selection
  void colorDoubleClicked();

protected:
  QScopedPointer<qSlicerTerminologyNavigatorWidgetPrivate> d_ptr;

private:
  Q_DECLARE_PRIVATE(qSlicerTerminologyNavigatorWidget);
  Q_DISABLE_COPY(qSlicerTerminologyNavigatorWidget);
};

#endif
